package enumate;

import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public interface Enumerable {
    String getValue();

    // 标记响应 json 值
    @JsonValue
    String getLabel();

    /**
     * 根据 value 获取枚举
     * <T extends Enum<?> & BaseEnum>: E 必须为一个枚举类，同时还必须实现 BaseEnum 接口
     */
    static <T extends Enum<?> & Enumerable> Optional<T> getByCode(Class<T> enumClass, String value) {
        return Stream.of(enumClass.getEnumConstants())
                .filter(enumerator -> Objects.equals(enumerator.getValue(), value))
                .findAny();
    }

    /**
     * 枚举转 Map
     */
    static <E extends Enum<?> & Enumerable> Map<String, String> enumToMap(Class<E> clazz) {
        // 合并时检查 key 是否重复
        BinaryOperator<String> merge = (u, v) -> {
            throw new IllegalStateException(String.format("Duplicate key %s", u));
        };
        return Arrays.stream(clazz.getEnumConstants())
                .collect(Collectors.toMap(Enumerable::getValue, Enumerable::getLabel, merge, LinkedHashMap::new));
    }

    /**
     * 根据 value 获取 label
     */
    @SuppressWarnings("all")
    static <T extends Enum<?> & Enumerable> String getNameByCode(Class<T> enumClass, String value) {
        return getByCode(enumClass, value).orElse((T) EmptyEnum.EMPTY).getLabel();
    }

    default boolean equalsValue(String value) {
        return this.getValue().equals(value);
    }

    default boolean isNotEquals(Enumerable enumerable) {
        return this != enumerable;
    }

    @Getter
    @AllArgsConstructor
    enum EmptyEnum implements Enumerable {
        EMPTY(null, ""),
        NULL(null, null);
        final String value;
        final String label;
    }
}